package com.liliudong.template.biz.service.sys.impl;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liliudong.template.biz.mapper.sys.SysMenuMapper;
import com.liliudong.template.biz.service.sys.SysMenuService;
import com.liliudong.template.biz.service.sys.SysRoleMenuService;
import com.liliudong.template.common.constant.EntityFieldConst;
import com.liliudong.template.common.constant.ExMessageEnum;
import com.liliudong.template.common.constant.SysMenuTypeEnum;
import com.liliudong.template.common.constant.SysMenuVisibleEnum;
import com.liliudong.template.common.convert.sys.SysMenuConvert;
import com.liliudong.template.common.dto.sys.SysMenuAddOrUpdateDTO;
import com.liliudong.template.common.dto.sys.SysMenuImportDTO;
import com.liliudong.template.common.entity.sys.SysMenu;
import com.liliudong.template.common.exception.BizException;
import com.liliudong.template.common.vo.sys.SysMenuDetailVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * sys菜单服务impl
 *
 * @author ldli5
 * @date 2024/06/18
 */
@Service
@RequiredArgsConstructor
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

	private final SysRoleMenuService sysRoleMenuService;

	@Override
	public List<SysMenu> listByRoleIdsIgnoreDataPermission(Collection<Long> roleIds) {
		return baseMapper.selectListByRoleIdsIgnoreDataPermission(roleIds);
	}

	@Override
	public Set<String> listPermissionByRoleIdsIgnoreDataPermission(Set<Long> roleIds) {
		return baseMapper.selectListByRoleIdsIgnoreDataPermission(roleIds).stream()
				.map(SysMenu::getPermission)
				.collect(Collectors.toSet());
	}

	@Override
	public Set<String> listPermissionIgnoreDataPermission() {
		return listIgnoreDataPermission()
				.stream()
				.map(SysMenu::getPermission)
				.collect(Collectors.toSet());
	}

	@Override
	public List<SysMenu> listIgnoreDataPermission() {
		return baseMapper.selectListIgnoreDataPermission();
	}

	@Override
	public void addOne(SysMenuAddOrUpdateDTO sysMenuAddOrUpdateDTO) {
		// 参数校验
		sysMenuAddOrUpdateDTO.paramsCheck();
		SysMenu sysMenu = SysMenuConvert.INSTANCE.dto2Entity(sysMenuAddOrUpdateDTO);
		// 保存菜单
		this.save(sysMenu);
	}

	@Override
	public void deleteById(Long id) {
		// 判断菜单是否被占用
		long count = sysRoleMenuService.countByMenuId(id);
		if (count > 0) {
			throw new BizException(ExMessageEnum.DATA_OCCUPIED);
		}
		// 判断其子级是否有菜单
		long countChildren = countByParentId(id);
		if (countChildren > 0) {
			throw new BizException(ExMessageEnum.DATA_OCCUPIED);
		}
		// 删除
		this.removeById(id);
	}

	/**
	 * 按父id计数
	 *
	 * @param id 身份证件
	 * @return long
	 */
	private long countByParentId(Long id) {
		return this.lambdaQuery().eq(SysMenu::getParentId, id).count();
	}

	@Override
	public void modifyById(Long id, SysMenuAddOrUpdateDTO sysMenuAddOrUpdateDTO) {
		// 参数校验
		sysMenuAddOrUpdateDTO.paramsCheck();
		SysMenu sysMenu = SysMenuConvert.INSTANCE.dto2Entity(sysMenuAddOrUpdateDTO);
		sysMenu.setId(id);
		this.updateById(sysMenu);
	}

	@Override
	public List<Tree<Long>> queryTree() {
		List<SysMenu> sysMenus = list();
		return menus2Tree(sysMenus);
	}

	@Override
	public List<Tree<Long>> menus2Tree(List<SysMenu> sysMenus) {
		return TreeUtil.build(sysMenus, 0L, (sysMenu, tree) -> {
			String component = sysMenu.getComponent();
			String icon = sysMenu.getIcon();
			String name = sysMenu.getName();
			Long parentId = sysMenu.getParentId();
			String permission = sysMenu.getPermission();
			Integer sort = sysMenu.getSort();
			SysMenuTypeEnum type = sysMenu.getType();
			SysMenuVisibleEnum visible = sysMenu.getVisible();
			Long id = sysMenu.getId();
			LocalDateTime createdAt = sysMenu.getCreatedAt();
			LocalDateTime updatedAt = sysMenu.getUpdatedAt();

			tree.setId(id);
			tree.setParentId(parentId);
			tree.setName(name);
			tree.setWeight(sort);
			tree.putExtra(EntityFieldConst.COMPONENT, component);
			tree.putExtra(EntityFieldConst.PERMISSION, permission);
			tree.putExtra(EntityFieldConst.VISIBLE, visible);
			tree.putExtra(EntityFieldConst.TYPE, type);
			tree.putExtra(EntityFieldConst.CREATED_AT, createdAt);
			tree.putExtra(EntityFieldConst.UPDATED_AT, updatedAt);
			tree.putExtra(EntityFieldConst.ICON, icon);
		});
	}

	@Override
	public SysMenuDetailVO detailById(Long id) {
		SysMenu sysMenu = this.getById(id);
		if (Objects.isNull(sysMenu)) {
			throw new BizException(ExMessageEnum.DATA_NOT_EXIST);
		}
		return SysMenuConvert.INSTANCE.entity2DetailVo(sysMenu);
	}

	@Override
	public List<SysMenu> listVisibleByRoleIdsIgnoreDataPermission(Collection<Long> roleIds) {
		return baseMapper.selectListVisibleByRoleIdsIgnoreDataPermission(roleIds);
	}

	@Override
	@Transactional
	public void importBatch(SysMenuImportDTO sysMenuImportDTO) {
		SysMenu sysMenu = SysMenuConvert.INSTANCE.importDto2Entity(sysMenuImportDTO);
		this.save(sysMenu);
		Optional.ofNullable(sysMenuImportDTO.getChildren())
				.map(SysMenuConvert.INSTANCE::importDtoList2EntityList)
				.ifPresent(children -> {
					children.forEach(entity -> entity.setParentId(sysMenu.getId()));
					this.saveBatch(children);
				});
	}
}
